package org.javaforever.gatescore.shiroauth.vue;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.javaforever.gatescore.core.FrontDomain;
import org.javaforever.gatescore.core.FrontManyToMany;
import org.javaforever.gatescore.core.JsGenerator;
import org.javaforever.gatescore.core.Statement;
import org.javaforever.gatescore.core.StatementList;
import org.javaforever.gatescore.core.Writeable;
import org.javaforever.gatescore.core.WriteableUtil;
import org.javaforever.gatescore.reports.LayoutComb;
import org.javaforever.gatescore.reports.ReportComb;
import org.javaforever.gatescore.shiroauth.ShiroAuthModule;
import org.javaforever.gatescore.utils.DomainUtil;

public class PermissionJSGenerator extends JsGenerator{
	protected List<FrontDomain> domains;
	protected List<FrontManyToMany> mtms;
	protected ShiroAuthModule shiroAuthModule;
	protected List<ReportComb> reports;
	protected List<LayoutComb> layouts;
	

	public PermissionJSGenerator() {
		super();
		this.standardName = "PermissionJS";
		this.fileName = "permission.js";
	}
	
	@Override
	public StatementList generateStatementList() {
		List<Writeable> sList = new ArrayList<Writeable>();
		sList.add(new Statement(1000L,0,"import { asyncRouterMap, constantRouterMap } from '@/router'"));
		sList.add(new Statement(2000L,0,""));
		sList.add(new Statement(3000L,0,"/**"));
		sList.add(new Statement(4000L,0,"* 通过meta.role判断是否与当前用户权限匹配"));
		sList.add(new Statement(5000L,0,"* @param roles"));
		sList.add(new Statement(6000L,0,"* @param perms"));
		sList.add(new Statement(7000L,0,"* @param route"));
		sList.add(new Statement(8000L,0,"*/"));
		sList.add(new Statement(9000L,0,"function hasPermission(roles, perms, route) {"));
		sList.add(new Statement(10000L,1,"if (!!route.name && !!perms) {"));
		sList.add(new Statement(11000L,2,"if (route.name === 'Index') return true"));
		sList.add(new Statement(12000L,2,"if (route.name === 'Pages') return true"));
		sList.add(new Statement(13000L,2,"if (route.name === 'ErrorPages') return true"));
		sList.add(new Statement(14000L,2,"if (route.name === 'Page401') return true"));
		sList.add(new Statement(15000L,2,"if (route.name === 'Page404') return true"));
		sList.add(new Statement(16000L,2,"if (route.name === 'ErrorLog') return true"));
		sList.add(new Statement(17000L,2,"if (route.name === 'I18n') return true"));
		sList.add(new Statement(18000L,2,"return hasAllPermissions(perms, route.name)"));
		sList.add(new Statement(19000L,1,"} else {"));
		sList.add(new Statement(20000L,2,"return true"));
		sList.add(new Statement(21000L,1,"}"));
		sList.add(new Statement(22000L,0,"}"));
		sList.add(new Statement(24000L,0,""));
		sList.add(new Statement(25000L,0,"function hasAllPermissions(perms, routeName) {"));
		sList.add(new Statement(26000L,1,"var requirePerms = lookUpPermissions(routeName)"));
		sList.add(new Statement(26500L,1,"if (requirePerms !== null && requirePerms.length === 1 && requirePerms[0] === 'authc') return true"));
		sList.add(new Statement(27000L,1,"if (perms === null || requirePerms === null || perms.length === 0 || requirePerms.length === 0) return false"));
		sList.add(new Statement(28000L,1,"for (var ritem of requirePerms) {"));
		sList.add(new Statement(29000L,2,"var found = false"));
		sList.add(new Statement(30000L,2,"for (var item of perms) {"));
		sList.add(new Statement(31000L,3,"if (item === ritem) found = true"));
		sList.add(new Statement(32000L,2,"}"));
		sList.add(new Statement(33000L,2,"if (found === false) return false"));
		sList.add(new Statement(34000L,1,"}"));
		sList.add(new Statement(35000L,1,"return true"));
		sList.add(new Statement(36000L,0,"}"));
		sList.add(new Statement(37000L,0,""));
		sList.add(new Statement(38000L,0,"function lookUpPermissions(routeName) {"));
		long serial = 39000L;
		sList.add(new Statement(serial,1,"if (routeName === 'Profile') return ['authc']"));
		serial += 1000L;
		Set<FrontDomain> adminDomains = new TreeSet<>();
		adminDomains.add(this.shiroAuthModule.getUserDomain());
		adminDomains.add(this.shiroAuthModule.getRoleDomain());
		adminDomains.add(this.shiroAuthModule.getPrivilegeDomain());
		if (this.getDomains()!=null&&this.getDomains().size()>0) {
			Set<FrontDomain> myDomains = new TreeSet<>();
			myDomains.addAll(this.getDomains());
			for (FrontDomain d:myDomains) {
				if (!DomainUtil.inDomainSet(d,adminDomains)) {
					sList.add(new Statement(serial,1,"if (routeName === '"+d.getStandardName()+"') return ['"+d.getStandardName()+"']"));
					serial += 2000L;
				}
			}
		}
		
		if (this.getMtms()!=null&&this.getMtms().size()>0) {
			for (FrontManyToMany mtm:this.getMtms()) {
				if (!DomainUtil.inDomainSet(mtm.getMaster(), adminDomains)) {
					sList.add(new Statement(serial,1,"if (routeName === '"+mtm.getStandardName()+"') return ['"+mtm.getMaster().getStandardName()+"']"));
				}
				serial += 2000L;
			}
		}
		if (this.getLayouts()!=null&&this.getLayouts().size()>0) {
			for (LayoutComb lc:this.getLayouts()) {
				Set<FrontDomain> mydomains = lc.getDomains();
				mydomains.removeAll(adminDomains);
				sList.add(new Statement(serial,1,"if (routeName === '"+lc.getStandardName()+"') return ["+DomainUtil.DomainSetNamesWithSingleQuote(mydomains)+"]"));
				serial += 2000L;
			}
		}
		if (this.getReports()!=null&&this.getReports().size()>0) {
			for (ReportComb rc:this.getReports()) {
				Set<FrontDomain> mydomains = rc.getDomains();
				mydomains.removeAll(adminDomains);
				sList.add(new Statement(serial,1,"if (routeName === '"+rc.getStandardName()+"') return ["+DomainUtil.DomainSetNamesWithSingleQuote(mydomains)+"]"));
				serial += 2000L;
			}
		}

		sList.add(new Statement(serial+41000L,0,"}"));
		sList.add(new Statement(serial+42000L,0,""));
		sList.add(new Statement(serial+43000L,0,"/**"));
		sList.add(new Statement(serial+44000L,0,"* 递归过滤异步路由表，返回符合用户角色权限的路由表"));
		sList.add(new Statement(serial+45000L,0,"* @param routes asyncRouterMap"));
		sList.add(new Statement(serial+46000L,0,"* @param roles"));
		sList.add(new Statement(serial+47000L,0,"* @param perms"));
		sList.add(new Statement(serial+48000L,0,"*/"));
		sList.add(new Statement(serial+49000L,0,"function filterAsyncRouter(routes, roles, perms) {"));
		sList.add(new Statement(serial+50000L,1,"const res = []"));
		sList.add(new Statement(serial+51000L,0,""));
		sList.add(new Statement(serial+52000L,1,"routes.forEach(route => {"));
		sList.add(new Statement(serial+53000L,2,"const tmp = { ...route }"));
		sList.add(new Statement(serial+54000L,2,"if (hasPermission(roles, perms, tmp)) {"));
		sList.add(new Statement(serial+55000L,3,"if (tmp.children && tmp.name === 'Pages') {"));
		sList.add(new Statement(serial+56000L,4,"tmp.children = filterAsyncRouter(tmp.children, roles, perms)"));
		sList.add(new Statement(serial+57000L,3,"}"));
		sList.add(new Statement(serial+58000L,3,"res.push(tmp)"));
		sList.add(new Statement(serial+59000L,2,"}"));
		sList.add(new Statement(serial+60000L,1,"})"));
		sList.add(new Statement(serial+61000L,0,""));
		sList.add(new Statement(serial+62000L,1,"return res"));
		sList.add(new Statement(serial+63000L,0,"}"));
		sList.add(new Statement(serial+64000L,0,""));
		sList.add(new Statement(serial+65000L,0,"const permission = {"));
		sList.add(new Statement(serial+66000L,1,"state: {"));
		sList.add(new Statement(serial+67000L,2,"routers: [],"));
		sList.add(new Statement(serial+68000L,2,"addRouters: []"));
		sList.add(new Statement(serial+69000L,1,"},"));
		sList.add(new Statement(serial+70000L,1,"mutations: {"));
		sList.add(new Statement(serial+71000L,2,"SET_ROUTERS: (state, routers) => {"));
		sList.add(new Statement(serial+72000L,3,"state.addRouters = routers"));
		sList.add(new Statement(serial+73000L,3,"state.routers = constantRouterMap.concat(routers)"));
		sList.add(new Statement(serial+74000L,2,"}"));
		sList.add(new Statement(serial+75000L,1,"},"));
		sList.add(new Statement(serial+76000L,1,"actions: {"));
		sList.add(new Statement(serial+77000L,2,"GenerateRoutes({ commit }, data) {"));
		sList.add(new Statement(serial+78000L,3,"return new Promise(resolve => {"));
		sList.add(new Statement(serial+79000L,4,"const { roles, perms } = data.roles"));
		sList.add(new Statement(serial+80000L,4,"let accessedRouters"));
		sList.add(new Statement(serial+81000L,4,"if (roles != null && roles.includes('admin')) {"));
		sList.add(new Statement(serial+82000L,5,"accessedRouters = asyncRouterMap"));
		sList.add(new Statement(serial+83000L,4,"} else {"));
		sList.add(new Statement(serial+84000L,5,"accessedRouters = filterAsyncRouter(asyncRouterMap, roles, perms)"));
		sList.add(new Statement(serial+85000L,4,"}"));
		sList.add(new Statement(serial+86000L,4,"commit('SET_ROUTERS', accessedRouters)"));
		sList.add(new Statement(serial+87000L,4,"resolve()"));
		sList.add(new Statement(serial+88000L,3,"})"));
		sList.add(new Statement(serial+89000L,2,"}"));
		sList.add(new Statement(serial+90000L,1,"}"));
		sList.add(new Statement(serial+91000L,0,"}"));
		sList.add(new Statement(serial+92000L,0,""));
		sList.add(new Statement(serial+93000L,0,"export default permission"));

		return WriteableUtil.merge(sList);
	}

	public List<FrontDomain> getDomains() {
		return domains;
	}

	public void setDomains(List<FrontDomain> domains) {
		this.domains = domains;
	}

	public List<FrontManyToMany> getMtms() {
		return mtms;
	}

	public void setMtms(List<FrontManyToMany> mtms) {
		this.mtms = mtms;
	}

	public ShiroAuthModule getShiroAuthModule() {
		return shiroAuthModule;
	}

	public void setShiroAuthModule(ShiroAuthModule shiroAuthModule) {
		this.shiroAuthModule = shiroAuthModule;
	}

	public List<ReportComb> getReports() {
		return reports;
	}

	public void setReports(List<ReportComb> reports) {
		this.reports = reports;
	}

	public List<LayoutComb> getLayouts() {
		return layouts;
	}

	public void setLayouts(List<LayoutComb> layouts) {
		this.layouts = layouts;
	}

}
